package com.kasax.plugin.app.transform

import com.android.build.api.transform.*
import com.android.build.gradle.internal.pipeline.TransformManager
import com.android.utils.FileUtils
import com.kasax.plugin.app.LogUtils
import com.kasax.plugin.app.visitor.addLog.AddLogClassVisitor
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter

/**
 * 自定义 Transform，用于在编译时修改字节码，插入日志记录逻辑。
 * 核心功能：
 * 1. 遍历所有类文件，过滤出目标类（非 R.class 和 BuildConfig.class）。
 * 2. 使用 ASM 修改字节码，插入日志记录逻辑。
 * 3. 支持增量编译和非增量编译模式。
 * 参考文档：https://juejin.cn/post/6965790738990776356
 */
class AddLogTransform extends Transform {

    @Override
    String getName() {
        return "AddLogTransform"
    }

    @Override
    Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }

    @Override
    Set<? super QualifiedContent.Scope> getScopes() {
        return TransformManager.SCOPE_FULL_PROJECT
    }

    @Override
    boolean isIncremental() {
        return false
    }

    @Override
    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
        super.transform(transformInvocation)

        LogUtils.d(getName(), "------------ ------------  transform 开始  ------------ ------------  ")
        def inputs = transformInvocation.inputs
        def outputProvider = transformInvocation.outputProvider
        inputs.each { TransformInput transformInput ->
            transformInput.directoryInputs.each { DirectoryInput directoryInput ->
                if (directoryInput.file.isDirectory()) {
                    FileUtils.getAllFiles(directoryInput.file).forEach { File file ->
                        def fileName = file.name
                        if (fileName.endsWith(".class") && fileName != "R.class" && !fileName.startsWith("R\$") && fileName != "BuildConfig.class") {
                            def clsPath = file.absolutePath
                            def cr = new ClassReader(file.bytes)
                            def cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS)
                            def visitor = new AddLogClassVisitor(cw)
                            cr.accept(visitor, ClassReader.EXPAND_FRAMES)

                            def bytes = cw.toByteArray()
                            def fos = new FileOutputStream(clsPath)
                            fos.write(bytes)
                            fos.close()
                        }
                    }
                }
                def destFile = outputProvider.getContentLocation(
                        directoryInput.name,
                        directoryInput.contentTypes,
                        directoryInput.scopes,
                        Format.DIRECTORY
                )
                FileUtils.copyDirectoryToDirectory(directoryInput.file, destFile)
            }
            transformInput.jarInputs.each { JarInput jarInput ->
                def jarFile = outputProvider.getContentLocation(
                        jarInput.name,
                        jarInput.contentTypes,
                        jarInput.scopes,
                        Format.JAR
                )
                handleJar(jarInput.file, jarFile)
            }
        }
        LogUtils.d(getName(), "------------ ------------  transform 结束  ------------ ------------  ")
    }

    void handleJar(File jarFile, File outPutFile) {
        LogUtils.d(getName(), "handleJar source-file-path: $jarFile.absolutePath , dest-file-path: $outPutFile.absolutePath")
        FileUtils.copyFile(jarFile, outPutFile)
    }
}